module.exports = app => {
  /*
  // 该事件一个 worker 进程只会触发一次，在 HTTP 服务完成启动后，会将 HTTP server 通过这个事件暴露出来给开发者。
  app.once('server', server => {
    // websocket
  });
  // 运行时有任何的异常被 onerror 插件捕获后，都会触发 error 事件，将错误对象和关联的上下文（如果有）暴露给开发者，可以进行自定义的日志记录上报等处理。
  app.on('error', (err, ctx) => {
    // report error
  });
  app.on('request', ctx => {
    // log receive request
  });
  app.on('response', ctx => {
    // ctx.starttime is set by framework
    const used = Date.now() - ctx.starttime;
    // log total cost
  });
  */
 
  // 添加请求字段的校验规则
  /*
  app.validator.addRule('json', (rule, value) => {
    try {
      JSON.parse(value);
    } catch (err) {
      return 'must be json string';
    }
  });
   */
 
  console.log('app.js app.config.env = ' + app.config.env);
 
  app.loog = function() {
    if (app.config.env == 'local') {
      console.log.apply(null, arguments);
    }
  };
  
  app.log = function(promptMessage, data) {
    if (app.config.env == 'local') {
      if (data == undefined) {
        console.log(promptMessage);
        console.log('第二个参数 data == undefined 是 true');
        console.log('第二个参数 data === undefined');
        console.log(data === undefined);
        console.log('第二个参数 data === null');
        console.log(data === null);
      } else {
        console.log('');
        console.log('>>>> ' + promptMessage + ' 开始');
        try {
          console.log(new Error(promptMessage));
        } catch(e) {
          // 
        }

        // console.log('\r\n>>>>---- ' + promptMessage + ' 开始 ----');
        console.log('==== typeof 的结果 ====');
        console.log(typeof data);
        console.log('==== 要打印的对象 ==== ');
        console.log(data);
        // 因为可能存在递归引用，此时字符串化会报错，所以使用try catch 来处理；
        try {
          console.log('==== 要打印的对象字符串化 ====');
          console.log(JSON.stringify(data));
        } catch (e) {
          if (e.message === 'Converting circular structure to JSON') {
            console.log('---- Converting circular structure to JSON 所以无法字符串化输出');
          }
          // 
        }
        console.log('---- ' + promptMessage + ' 结束 ----<<<<\r\n');
      }
    }
  };

  app.info = function() {
    if (app.config.env == 'local') {
      console.info.apply(null, arguments);
    }
  };

  app.warn = function() {
    if (app.config.env == 'local') {
      console.warn.apply(null, arguments);
    }
  };

  app.error = function() {
    if (app.config.env == 'local') {
      console.error.apply(null, arguments);
    }
  };

  app.beforeStart(async () => {
    // 应用启动监听端口前会执行这里
    // 应用会等待这个函数执行完成才启动（只在启动时执行一次，后续每次请求时不会再次执行。当然代码变化后会自动重启项目，此时也会执行这里。）
    // 但是这个不是入口文件，不能使用 node app.js 来执行；
    
    // app.cities = await app.curl('http://example.com/city.json', {
    // let res = await app.curl('http://localhost/city.json', {
    //   method: 'GET',
    //   dataType: 'json',
    // });
    // console.log(res);

    // 当执行下面的代码，在 news 这个 service 中又通过 controller 来访问资源时，
    // 就会导致项目启动失败，具体原因不明--我估计是因为项目还未成功启动，所以不能通过控制器来访自身的东西；
    // const ctx = app.createAnonymousContext();
    // let res2 = await ctx.service.news.list(1);
    // console.log(res2);
    
    // 测试时是在 app/middleware/console.js 中给 ctx 添加的这些个方法；
    // 但中间件是请求级别的，只有发送请求才会执行，所以项目初始化时不执行，自然就没有下面的方法了。
    // console.log(ctx.loog);
    // console.log(ctx.log);
    

    // 后来想了下，应该在这里添加 loog和log方法，不应该在中间件内，因为中间件时请求级别的，每次请求都会执行一次，都要添加一次，肯定是浪费的。
    // 加到 app 上，而不是 context/ctx 上；
    // 不写在这里了，写在外面；


    // 也可以通过以下方式来调用 Service
    // const ctx = app.createAnonymousContext();
    // app.cities = await ctx.service.cities.load();
  });
};